#pragma once

#include "../common/Log.hpp"
#include "../common/SqliteHelper.hpp"
#include "../common/FileHelper.hpp"
#include "../common/message.pb.h"
#include "MsgQueue.hpp"
#include "MsgQueueMapper.hpp"
#include <google/protobuf/map.h>
#include <iostream>
#include <string>
#include <unordered_map>
#include <mutex>
#include <memory>

namespace micromq
{
    class MsgQueueManager
    {
    public:
        using ptr = std::shared_ptr<MsgQueueManager>;
    public:
        MsgQueueManager(const std::string& dbFileName): _mapper(dbFileName)
        {
            _msgQueues = _mapper.selectAll();
        }

        bool declareMsgQueue(const std::string& name, bool durable, bool exclusive, bool autoDelete, 
            const google::protobuf::Map<std::string, std::string>& args)
        {
            std::unique_lock<std::mutex> lock(_mtx);
            if(_msgQueues.find(name) != _msgQueues.end()) return false;
            auto msgQueues = std::make_shared<MsgQueue>(name, durable, exclusive, autoDelete, args);
            if(durable = true) _mapper.insertMsgQueue(msgQueues);
            _msgQueues[name] = msgQueues;
            return true;
        }

        void removeMsgQueue(const std::string& name)
        {
            std::unique_lock<std::mutex> lock(_mtx);
            if(_msgQueues.find(name) == _msgQueues.end()) return;
            if(_msgQueues[name]->_durable == true) _mapper.deleteMsgQueue(name);
            _msgQueues.erase(name);
        }

        MsgQueue::ptr getMsgQueue(const std::string& name)
        {
            std::unique_lock<std::mutex> lock(_mtx);
            if(_msgQueues.find(name) == _msgQueues.end()) return nullptr;
            return _msgQueues[name];
        }

        std::unordered_map<std::string, MsgQueue::ptr> getAllMsgQueue()
        {
            std::unique_lock<std::mutex> lock(_mtx);
            return _msgQueues;
        }

        bool isExists(const std::string& name)
        {
            std::unique_lock<std::mutex> lock(_mtx);
            return _msgQueues.find(name) != _msgQueues.end();
        }

        int size()
        {
            return _msgQueues.size();
        }

        void clear()
        {
            std::unique_lock<std::mutex> lock(_mtx);
            _mapper.removeTable();
            _msgQueues.clear();
        }

        ~MsgQueueManager()
        {}
    private:
        MsgQueueMapper _mapper;
        std::unordered_map<std::string, MsgQueue::ptr> _msgQueues;
        std::mutex _mtx;
    };
}